package com.weilus.util.crypt;

import com.weilus.dto.ErrorResp;
import com.weilus.dto.RespEntity;
import com.weilus.util.encrypt.RSA;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

@RestControllerAdvice
@ConfigurationProperties(prefix="http.rsa")
public class RestRequestAdvice implements RequestBodyAdvice {
	public static Logger log = LoggerFactory.getLogger(RestRequestAdvice.class);
	
	private String privateKey;

	@ExceptionHandler(CryptException.class)
	public RespEntity decryptException(CryptException e) {
		return new ErrorResp(e.getCode(),e.getMsg());
	}
	
	@Override
	public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return !StringUtils.isEmpty(privateKey) && existAnnationsInParameter(methodParameter,RsaDecrypt.class);
	}

	@Override
	public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return null;
	}
	@Override
	public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
		return new HttpInputMessage() {
			@Override
			public HttpHeaders getHeaders() {
				return inputMessage.getHeaders();
			}
			@Override
			public InputStream getBody() throws IOException {
				StringBuilder mi = new StringBuilder();
	            long contentLength = inputMessage.getHeaders().getContentLength();
	            if (contentLength > 0) {
		            byte buffer[] = new byte[1024];
		            int length;
		            while((length = inputMessage.getBody().read(buffer))!=-1){
		            	mi.append(new String(buffer,0 ,length));
		            }
		            log.info("请求密文===="+mi.toString());
					try {
						byte[] plainText = RSA.decrypt(RSA.getPrivateKey(privateKey),mi.toString().getBytes());
						return new ByteArrayInputStream(plainText);
					} catch (Exception e) {
						throw new CryptException(CryptError.RSA_DECRYPT_ERROR);
					}
	            }
	            return null;
			}
		};
	}
	
	@Override
	public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}
	
	public String getPrivateKey() {
		return privateKey;
	}
	public void setPrivateKey(String privateKey) {
		this.privateKey = privateKey;
	}
	
	private boolean existAnnationsInParameter(MethodParameter methodParameter, Class<?> clazz){
		for (Annotation[] annotations : methodParameter.getMethod().getParameterAnnotations()){
			for (Annotation annotation : annotations) {
				if(clazz.getName().equals(annotation.annotationType().getName()))return true;
			}
		}
		return false;
	}
	
	
}
